﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Web.UI;
using System.Web.UI.WebControls;
using StockholmsStad.Web.UI.Class.Utilities;

namespace StockholmsStad.Web.UI.Controls
{
    /// <summary>
    /// Webcontrol som visar en lista av datum som tre (eller två) dropdownlistor.
    /// De tre listorna innhåller år och månad; veckodag och datum; samt timme och minuter.
    /// När år och månad-listan ändras, så uppdateras underliggande listor för att visa
    /// giltiga dagar och tider för månaden. Motsvarande gäller för veckodag och datum
    /// och underliggande tider.
    /// Kontrollen använder sig av Ajax och det är viktigt att Dates fylls i vid
    /// förändringar, dvs sätt Dates varje gång i contanerns Load_Page.
    /// </summary>
    public partial class DateTimeFields : UserControl
    {
        private static readonly DateTimeFormatInfo FORMAT_INFO = new CultureInfo("sv-SE", false).DateTimeFormat;

        /// <summary>
        /// Vilka datum som ska visas i dropdownlistorna
        /// </summary>
        public IEnumerable<DateTime> Dates { get; set; }

        /// <summary>
        /// Vilket datum som ska vara förvalt i listorna.
        /// Om null sätts, så blir det första datumet förvalt
        /// </summary>
        public DateTime? SelectedDate
        {
            get
            {
                string value = ddlTime.SelectedValue;
                if (string.IsNullOrEmpty(value))
                    return null;
                return new DateTime(long.Parse(value));
            }
            set
            {
                if (value == null)
                {
                    InitTimeblocks(GetEarliestDate);
                }
                else
                {
                    Checked = true;
                    InitTimeblocks(value);
                }
            }
        }

        /// <summary>
        /// Checkboxen ikryssad
        /// </summary>
        public bool Checked
        {
            get { return cbxConfirm.Checked; }
            set { cbxConfirm.Checked = value; }
        }

        /// <summary>
        /// Vilken text som ska stå i checkboxen på sidan om dropdownlistorna
        /// </summary>
        public string CheckboxText
        {
            get { return cbxConfirm.Text; }
            set { cbxConfirm.Text = value; }
        }

        /// <summary>
        /// Om dropdownlistan för tider ska vara synlig eller ej
        /// </summary>
        public bool TimeDropDownVisible
        {
            get { return ddlTime.Visible; }
            set
            {
                ddlTime.Visible = value;
                lblTime.Visible = value;
            }
        }

        /// <summary>
        /// Tar fram det första datumet
        /// </summary>
        private DateTime? GetEarliestDate
        {
            get { return DateTimeUtil.GetEarliestDate(Dates); }
        }


        /// <summary>
        /// Körs när sidan laddas
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void Page_Load(object sender, EventArgs e)
        {
        }

        /// <summary>
        /// Valt värde i dropdownlistan med veckodag och datum har ändrats
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void ddlDay_SelectedIndexChanged(object sender, EventArgs e)
        {
            InitTimeblocks(new DateTime(long.Parse(ddlDay.SelectedValue)));
        }

        /// <summary>
        /// Valt värde i dropdownlistan med år och månad har ändrats
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void ddlMonth_SelectedIndexChanged(object sender, EventArgs e)
        {
            InitTimeblocks(new DateTime(long.Parse(ddlMonth.SelectedValue)));
        }

        private DropDownLists GetDropDownLists(DateTime selectedDate)
        {
            int dateYear = selectedDate.Year;
            int dateMonth = selectedDate.Month;
            int dateDayOfYear = selectedDate.DayOfYear;
            var months = new ListItemSet();
            var days = new ListItemSet();
            var times = new ListItemSet();
            foreach (DateTime date in Dates)
            {
                // add all months to dropdown
                months.Add(new ListItem(GetMonthText(date), date.Ticks.ToString()));
                // Add only matching days
                if (date.Year == dateYear &&
                    date.Month == dateMonth)
                {
                    days.Add(new ListItem(GetDayText(date), date.Ticks.ToString()));
                    // Add times if both month and day match
                    if (date.DayOfYear == dateDayOfYear)
                    {
                        times.Add(new ListItem(GetTimeText(date), date.Ticks.ToString()));
                    }
                }
            }
            return new DropDownLists
                       {
                           Days = days,
                           Months = months,
                           Times = times,
                       };
        }

        private void InitTimeblocks(DateTime? date)
        {
            ddlMonth.Items.Clear();
            ddlDay.Items.Clear();
            ddlTime.Items.Clear();
            if (date == null)
            {
                return;
            }
            DropDownLists lists = GetDropDownLists(date.Value);
            fillDropDownList(lists.Months, ddlMonth, GetMonthText, date.Value);
            fillDropDownList(lists.Days, ddlDay, GetDayText, date.Value);
            fillDropDownList(lists.Times, ddlTime, GetTimeText, date.Value);
        }

        private void fillDropDownList(IEnumerable<ListItem> items, ListControl dropDownList,
                                      Func<DateTime, string> GetDateText, DateTime dateTime)
        {
            dropDownList.Items.AddRange(items.ToArray());
            ListItem text = dropDownList.Items.FindByText(GetDateText(dateTime));
            if (text == null)
            {
                text = new ListItem(GetDateText(dateTime), dateTime.Ticks.ToString());
                dropDownList.Items.Insert(0, text);
            }
            text.Selected = true;
        }

        private static string GetMonthText(DateTime dateTime)
        {
            return dateTime.ToString("yyyy-MM");
        }

        private static string GetDayText(DateTime dateTime)
        {
            return dateTime.ToString("dddd d", FORMAT_INFO);
        }

        private static string GetTimeText(DateTime dateTime)
        {
            return dateTime.ToString("HH:mm");
        }

        #region Nested type: DropDownLists

        /// <summary>
        /// Hjälpklass som innehåller vilka datum och tider som visas i de tre dropdownlistorna
        /// </summary>
        public class DropDownLists
        {
            /// <summary>
            /// År och månader
            /// </summary>
            public ICollection<ListItem> Months { get; set; }

            /// <summary>
            /// Veckodag och datum
            /// </summary>
            public ICollection<ListItem> Days { get; set; }

            /// <summary>
            /// Timme och minut
            /// </summary>
            public ICollection<ListItem> Times { get; set; }
        }

        #endregion
    }
}